# -*- coding: utf-8 -*-
# ChanStrategy.py

from ctaTemplate import CtaTemplate
from vtConstant import *
from czsc import CZSC, analyze
from utils import MinKLineGenerator
from vtObject import KLineData, TickData
import numpy as np
import pandas as pd


class ChanStrategy(CtaTemplate):
    def __init__(self):
        """初始化缠论策略"""
        super().__init__()

        # 策略参数映射表
        self.paramMap = {
            'exchange': '交易所',
            'vtSymbol': '合约',
            'periods': '显示周期',
            'show_levels': '显示级别',
            'show_elements': '显示元素',
            'kline_style': 'K线类型',
        }

        # 变量映射表
        self.varMap = {
            'trading': '交易中',
            'current_period': '当前周期',
            'pos': '持仓',
        }

        # 初始化参数
        self.exchange = "CZCE"
        self.vtSymbol = "SA601"
        self.periods = ['15秒', '1分钟', '5分钟', '30分钟', '日线']
        self.show_levels = [1, 2, 3]  # 1:次级别, 2:本级别, 3:上级别
        self.show_elements = ['分型', '笔', '线段', '中枢', '特征序列', '买卖点']
        self.current_period = '5分钟'
        self.kline_style = "M5"  # K线类型，例如M1, M5, M15等

        # 初始化缠论分析器
        self.analyzers = {}

        # K线生成器
        self.kline_generator = None

        # 存储K线数据
        self.bars = {}

        # 日志
        self.writeCtaLog("缠论策略初始化成功!")

        # 模拟生成K线数据
        self.test_with_mock_data()

    def onInit(self):
        """策略初始化回调"""
        self.writeCtaLog(f"策略初始化完成: {self.vtSymbol}")

        # 初始化K线存储
        self.init_bars_storage()

        # 初始化分析器（延迟到有数据时）
        self.writeCtaLog("分析器将在有数据时初始化")

    def init_bars_storage(self):
        """初始化K线数据存储"""
        for period in self.periods:
            self.bars[period] = []
        self.writeCtaLog("已初始化K线数据存储")

    def init_analyzer(self, period):
        """初始化单个周期的分析器（仅在需要时）"""
        if period not in self.analyzers and self.bars[period]:
            try:
                self.analyzers[period] = CZSC(bars=self.bars[period], freq=period)
                self.writeCtaLog(f"已初始化{period}周期的分析器")
            except Exception as e:
                self.writeCtaLog(f"初始化{period}周期分析器时出错: {str(e)}")

    def onBar(self, bar: KLineData):
        """处理新K线（由MinKLineGenerator回调）"""
        if not bar:
            self.writeCtaLog("收到空的K线数据")
            return

        # 添加详细日志
        self.writeCtaLog(
            f"收到K线: {bar.datetime} O={bar.open}, H={bar.high}, L={bar.low}, C={bar.close}, V={bar.volume}")

        # 更新所有周期的K线数据
        self.update_bars(bar)

        # 确保分析器已初始化
        self.init_analyzer(self.current_period)

        # 更新分析器
        self.update_analyzers(bar)

        # 执行缠论分析
        self.analyze_chan()

        # 检测买卖点
        self.detect_signals()

    def update_bars(self, bar):
        """更新所有周期的K线数据"""
        # 只更新当前周期的K线数据
        if self.current_period in self.bars:
            self.bars[self.current_period].append(bar)
            self.writeCtaLog(
                f"已更新{self.current_period}周期的K线数据，当前数量: {len(self.bars[self.current_period])}")

    def update_analyzers(self, bar):
        """更新分析器数据"""
        # 只更新当前周期的分析器
        if self.current_period in self.analyzers and self.analyzers[self.current_period] is not None:
            try:
                self.analyzers[self.current_period].update(bar)
            except Exception as e:
                self.writeCtaLog(f"更新{self.current_period}分析器时出错: {str(e)}")

    def analyze_chan(self):
        """执行缠论分析"""
        if self.current_period not in self.analyzers:
            return

        analyzer = self.analyzers[self.current_period]

        # 处理包含关系
        analyzer.process_contains()

        # 识别分型
        analyzer.process_fenxing()

        # 识别笔
        analyzer.process_bi()

        # 识别线段
        analyzer.process_duan()

        # 识别中枢
        analyzer.process_zhongshu()

        # 打印分析结果
        self.writeCtaLog(f"分型数量: {len(analyzer.fenxings)}")
        self.writeCtaLog(f"笔数量: {len(analyzer.bis)}")
        self.writeCtaLog(f"中枢数量: {len(analyzer.zhongshus)}")

    def detect_signals(self):
        """检测买卖点信号"""
        if self.current_period not in self.analyzers:
            return

        analyzer = self.analyzers[self.current_period]

        # 检测第一类买点（底分型+背驰）
        for bi in analyzer.bis:
            if bi.direction == "down" and analyzer.is_divergence(bi):
                self.writeCtaLog(f"检测到一类买点: {bi.end_time} {bi.end_price}")

        # 检测第二类买点
        # ...

    def onTick(self, tick: TickData):
        """处理Tick数据（由策略引擎回调）"""
        if tick:
            # 添加Tick数据日志
            self.writeCtaLog(f"收到Tick: {tick.datetime} 最新价={tick.lastPrice}, 成交量={tick.volume}")

        if self.kline_generator:
            try:
                self.kline_generator.tick_to_kline(tick)
            except Exception as e:
                self.writeCtaLog(f"处理Tick数据时出错: {str(e)}")

    def onStart(self):
        """策略启动回调"""
        self.trading = True
        self.writeCtaLog("策略启动")

        # 添加详细日志
        self.writeCtaLog(f"交易品种: {self.vtSymbol}, 交易所: {self.exchange}")
        self.writeCtaLog(f"K线周期: {self.kline_style}")

        # 启动K线生成器
        try:
            self.kline_generator = MinKLineGenerator(
                real_time_callback=self.real_time_callback,
                callback=self.onBar,
                exchange=self.exchange,
                instrument=self.vtSymbol,
                style=self.kline_style
            )
            self.writeCtaLog("K线生成器初始化成功")

            # 开始推送K线
            self.kline_generator.start_push_scheduler()
            self.writeCtaLog("K线推送已启动")
        except Exception as e:
            self.writeCtaLog(f"启动K线生成器时出错: {str(e)}")

        # 开始推送K线
        self.kline_generator.start_push_scheduler()

    def onStop(self):
        """策略停止回调"""
        self.trading = False
        if self.kline_generator:
            self.kline_generator.stop_push_scheduler()
        self.writeCtaLog("策略停止")

    def real_time_callback(self, kline: KLineData):
        """实时K线回调（用于实时更新界面）"""
        # 暂时不处理实时更新
        pass



def test_with_mock_data(self):
    """使用模拟数据测试策略"""

    class MockTick:
        def __init__(self):
            self.datetime = datetime.now()
            self.lastPrice = 100.0
            self.volume = 1000

    class MockBar:
        def __init__(self):
            self.datetime = datetime.now()
            self.open = 99.5
            self.high = 101.0
            self.low = 99.0
            self.close = 100.5
            self.volume = 2000

    # 测试Tick处理
    self.writeCtaLog("=== 开始模拟测试 ===")
    self.onStart()

    # 发送模拟Tick
    for _ in range(10):
        tick = MockTick()
        self.onTick(tick)
        time.sleep(0.1)

    # 发送模拟K线
    bar = MockBar()
    self.onBar(bar)

    self.writeCtaLog("=== 模拟测试完成 ===")


def create_strategy():
    """创建策略实例"""
    return ChanStrategy()
